package com.xuecheng.search;

import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@SpringBootTest
@RunWith(SpringRunner.class)
public class ElasticTest01 {

    @Autowired
    private RestClient restClient;
    @Autowired
    private RestHighLevelClient restHighLevelClient;

    /**
     * @Description: 删除索引库测试
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void delleteIndex() throws IOException {
//         创建删除索引请求对象
        DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest("xc_course");
//        删除索引
        DeleteIndexResponse indexResponse = restHighLevelClient.indices().delete(deleteIndexRequest);
//        响应结果
        boolean acknowledged = indexResponse.isAcknowledged();
        System.out.println(acknowledged);
    }

    /**
     * @Description: 创建索引库
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void creatIndex() throws IOException {
//        创建索引请求对象
        CreateIndexRequest createIndexRequese = new CreateIndexRequest("xc_course");
//        设置索引参数
        createIndexRequese.settings(Settings.builder().put("number_of_shards", 1).put("number_of_replicas", 0));
        //        设置映射
        createIndexRequese.mapping("doc", " {\n" + " \t\"properties\": {\n" + " \"name\": {\n" + " \"type\": \"text\",\n" + " \"analyzer\":\"ik_max_word\",\n" + " \"search_analyzer\":\"ik_smart\"\n" + " },\n" + " \"description\": {\n" + " \"type\": \"text\",\n" + " \"analyzer\":\"ik_max_word\",\n" + " \"search_analyzer\":\"ik_smart\"\n" + " },\n" + " \"studymodel\": {\n" + " \"type\": \"keyword\"\n" + " },\n" + " \"price\": {\n" + " \"type\": \"float\"\n" + " }\n" + " }\n" + "}",
                XContentType.JSON);
//        创建索引
        CreateIndexResponse createIndexResponse = restHighLevelClient.indices().create(createIndexRequese);
        boolean acknowledged = createIndexResponse.isAcknowledged();
        System.out.println(acknowledged);

    }

    /**
     * @Description: 创建文档
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void createDocument() throws IOException {
//    创建添加文档请求对象
        IndexRequest indexRequest = new IndexRequest("xc_course", "doc");
//        准备json对象
        Map<String, Object> jsonMap = new HashMap<>();
        jsonMap.put("name", "spring cloud实战");
        jsonMap.put("description", "本课程主要从四个章节进行讲解： 1.微服务架构入门 2.spring cloud 基础入门 3.实战Spring Boot 4.注册中心eureka。");
        jsonMap.put("studymodel", "201001");
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy‐MM‐dd HH:mm:ss");
        jsonMap.put("timestamp", dateFormat.format(new Date()));
        jsonMap.put("price", 5.6f);
//        指定索引文档内容
        IndexRequest source = indexRequest.source(jsonMap);
//        索引响应对象
        IndexResponse index = restHighLevelClient.index(source);
        DocWriteResponse.Result result = index.getResult();
        System.out.println(result);

    }

    /**
     * @Description: 创建搜索
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void searchIndex() throws IOException {
        //    创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("xc_course");
//    指定类型
        searchRequest.types("doc");
//        搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置搜索方式
        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//        设置过滤字段,第一个结果集表示要显示的字段，第二个结果集表示不要显示的字段，
        searchSourceBuilder.fetchSource(new String[]{"name", "description"}, new String[]{});
//        搜索请求中设置搜索源对象
        SearchRequest source = searchRequest.source(searchSourceBuilder);
//        进行搜索
        SearchResponse searchResponse = restHighLevelClient.search(source);
//        搜索的结果
        SearchHits hits = searchResponse.getHits();
//        得到匹配度搞得数据
        SearchHit[] hitsHits = hits.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
//        遍历结果
        for (SearchHit sh : hitsHits
        ) {
            Map<String, Object> sourceAsMap = sh.getSourceAsMap();
            Object name = sourceAsMap.get("name");
            Object description = sourceAsMap.get("description");
            System.out.println(name);
            System.out.println(description);
        }
    }

    /**
     * @Description: 分页搜索
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void searchIndexBypage() throws IOException {
        //    创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("xc_course");
//    指定类型
        searchRequest.types("doc");
//        搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置分页参数
//        设置起始记录数，及每页显示数
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(2);
//        设置搜索方式
//        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchSourceBuilder.query(QueryBuilders.termQuery("name", "开发"));
//        设置过滤字段,第一个结果集表示要显示的字段，第二个结果集表示不要显示的字段，
        searchSourceBuilder.fetchSource(new String[]{"name", "description"}, new String[]{});
//        搜索请求中设置搜索源对象
        SearchRequest source = searchRequest.source(searchSourceBuilder);
//        进行搜索
        SearchResponse searchResponse = restHighLevelClient.search(source);
//        搜索的结果
        SearchHits hits = searchResponse.getHits();
//        得到匹配度搞得数据
        SearchHit[] hitsHits = hits.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
//        遍历结果
        for (SearchHit sh : hitsHits
        ) {
            Map<String, Object> sourceAsMap = sh.getSourceAsMap();
            Object name = sourceAsMap.get("name");
            Object description = sourceAsMap.get("description");
            System.out.println(name);
            System.out.println(description);
        }


    }

    /**
     * @Description: 根据id查询
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void searchIndexByIds() throws IOException {
        //    创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("xc_course");
//    指定类型
        searchRequest.types("doc");
//        搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置分页参数
//        设置起始记录数，及每页显示数
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(2);
//        设置搜索方式
//        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        String[] ids = new String[]{"1", "2"};
        searchSourceBuilder.query(QueryBuilders.termsQuery("_id", ids));
//        设置过滤字段,第一个结果集表示要显示的字段，第二个结果集表示不要显示的字段，
        searchSourceBuilder.fetchSource(new String[]{"name", "description"}, new String[]{});
//        搜索请求中设置搜索源对象
        SearchRequest source = searchRequest.source(searchSourceBuilder);
//        进行搜索
        SearchResponse searchResponse = restHighLevelClient.search(source);
//        搜索的结果
        SearchHits hits = searchResponse.getHits();
//        得到匹配度搞得数据
        SearchHit[] hitsHits = hits.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
//        遍历结果
        for (SearchHit sh : hitsHits
        ) {
            Map<String, Object> sourceAsMap = sh.getSourceAsMap();
            Object name = sourceAsMap.get("name");
            Object description = sourceAsMap.get("description");
            System.out.println(name);
            System.out.println(description);
        }


    }

    /**
     * @Description: 模糊匹配查询, 单个域中
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void searchIndexByMatch() throws IOException {
        //    创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("xc_course");
//    指定类型
        searchRequest.types("doc");
//        搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置分页参数
//        设置起始记录数，及每页显示数
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(2);
//        设置搜索方式
//        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        String[] ids = new String[]{"1", "2"};
        searchSourceBuilder.query(QueryBuilders.matchQuery("name", "spring开发框架").minimumShouldMatch("80%"));
//        设置过滤字段,第一个结果集表示要显示的字段，第二个结果集表示不要显示的字段，
        searchSourceBuilder.fetchSource(new String[]{"name", "description"}, new String[]{});
//        搜索请求中设置搜索源对象
        SearchRequest source = searchRequest.source(searchSourceBuilder);
//        进行搜索
        SearchResponse searchResponse = restHighLevelClient.search(source);
//        搜索的结果
        SearchHits hits = searchResponse.getHits();
//        得到匹配度搞得数据
        SearchHit[] hitsHits = hits.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
//        遍历结果
        for (SearchHit sh : hitsHits
        ) {
            Map<String, Object> sourceAsMap = sh.getSourceAsMap();
            Object name = sourceAsMap.get("name");
            Object description = sourceAsMap.get("description");
            System.out.println(name);
            System.out.println(description);
        }


    }

    /**
     * @Description: 模糊匹配查询, 多个域中
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void searchIndexByMultiMatch() throws IOException {
        //    创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("xc_course");
//    指定类型
        searchRequest.types("doc");
//        搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置分页参数
//        设置起始记录数，及每页显示数
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(2);
//        设置搜索方式
//        searchSourceBuilder.query(QueryBuilders.matchAllQuery());
        searchSourceBuilder.query(QueryBuilders.multiMatchQuery("java css", "name", "description").minimumShouldMatch("50%").field("name", 5));
//        设置过滤字段,第一个结果集表示要显示的字段，第二个结果集表示不要显示的字段，
        searchSourceBuilder.fetchSource(new String[]{"name", "description"}, new String[]{});
//        搜索请求中设置搜索源对象
        SearchRequest source = searchRequest.source(searchSourceBuilder);
//        进行搜索
        SearchResponse searchResponse = restHighLevelClient.search(source);
//        搜索的结果
        SearchHits hits = searchResponse.getHits();
//        得到匹配度搞得数据
        SearchHit[] hitsHits = hits.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
//        遍历结果
        for (SearchHit sh : hitsHits
        ) {
            Map<String, Object> sourceAsMap = sh.getSourceAsMap();
            Object name = sourceAsMap.get("name");
            Object description = sourceAsMap.get("description");
            System.out.println(name);
            System.out.println(description);
        }


    }

    /**
     * @Description: bool查询, 多个条件
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void searchIndexByboolMatch() throws IOException {
        //    创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("xc_course");
//    指定类型
        searchRequest.types("doc");
//        搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置分页参数
//        设置起始记录数，及每页显示数
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(2);
//        设置搜索方式条件
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("开发 css", "name", "description").minimumShouldMatch("50%").field("name", 5);
        TermQueryBuilder studymodel = QueryBuilders.termQuery("studymodel", "201002");
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(multiMatchQueryBuilder);
        boolQueryBuilder.must(studymodel);

        searchSourceBuilder.query(boolQueryBuilder);
//        设置过滤字段,第一个结果集表示要显示的字段，第二个结果集表示不要显示的字段，
        searchSourceBuilder.fetchSource(new String[]{"name", "description"}, new String[]{});
//        搜索请求中设置搜索源对象
        SearchRequest source = searchRequest.source(searchSourceBuilder);
//        进行搜索
        SearchResponse searchResponse = restHighLevelClient.search(source);
//        搜索的结果
        SearchHits hits = searchResponse.getHits();
//        得到匹配度搞得数据
        SearchHit[] hitsHits = hits.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
//        遍历结果
        for (SearchHit sh : hitsHits
        ) {
            Map<String, Object> sourceAsMap = sh.getSourceAsMap();
            Object name = sourceAsMap.get("name");
            Object description = sourceAsMap.get("description");
            System.out.println(name);
            System.out.println(description);
        }


    }

    /**
     * @Description: 查询结果, 过滤器进行过滤筛选
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void searchIndexByFilterMatch() throws IOException {
        //    创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("xc_course");
//    指定类型
        searchRequest.types("doc");
//        搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置分页参数
//        设置起始记录数，及每页显示数
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(2);
//        设置搜索方式条件
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("开发 css", "name", "description").minimumShouldMatch("50%").field("name", 5);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(multiMatchQueryBuilder);
//        设置过滤条件
//        boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel","201002"));
        boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gt(30).lt(50));


        searchSourceBuilder.query(boolQueryBuilder);
//        设置过滤字段,第一个结果集表示要显示的字段，第二个结果集表示不要显示的字段，
        searchSourceBuilder.fetchSource(new String[]{"name", "description"}, new String[]{});
//        搜索请求中设置搜索源对象
        SearchRequest source = searchRequest.source(searchSourceBuilder);
//        进行搜索
        SearchResponse searchResponse = restHighLevelClient.search(source);
//        搜索的结果
        SearchHits hits = searchResponse.getHits();
//        得到匹配度搞得数据
        SearchHit[] hitsHits = hits.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
//        遍历结果
        for (SearchHit sh : hitsHits
        ) {
            Map<String, Object> sourceAsMap = sh.getSourceAsMap();
            Object name = sourceAsMap.get("name");
            Object description = sourceAsMap.get("description");
            System.out.println(name);
            System.out.println(description);
        }


    }

    /**
     * @Description: 排序查询
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void searchIndexBySortMatch() throws IOException {
        //    创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("xc_course");
//    指定类型
        searchRequest.types("doc");
//        搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置分页参数
//        设置起始记录数，及每页显示数
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(3);
//        设置排序条件
        searchSourceBuilder.sort("studymodel", SortOrder.ASC);
        searchSourceBuilder.sort("price", SortOrder.DESC);
//        设置搜索方式条件
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("开发 css", "name", "description").minimumShouldMatch("50%").field("name", 5);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(multiMatchQueryBuilder);
//        设置过滤条件
//        boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel","201002"));
//        boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gt(30).lt(50));


        searchSourceBuilder.query(boolQueryBuilder);
//        设置过滤字段,第一个结果集表示要显示的字段，第二个结果集表示不要显示的字段，
        searchSourceBuilder.fetchSource(new String[]{"name", "description"}, new String[]{});
//        搜索请求中设置搜索源对象
        SearchRequest source = searchRequest.source(searchSourceBuilder);
//        进行搜索
        SearchResponse searchResponse = restHighLevelClient.search(source);
//        搜索的结果
        SearchHits hits = searchResponse.getHits();
//        得到匹配度搞得数据
        SearchHit[] hitsHits = hits.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);
//        遍历结果
        for (SearchHit sh : hitsHits
        ) {
            Map<String, Object> sourceAsMap = sh.getSourceAsMap();
            Object name = sourceAsMap.get("name");
            Object description = sourceAsMap.get("description");
            System.out.println(name);
            System.out.println(description);
        }


    }

    /**
     * @Description: 高亮显示
     * @Param:
     * @return:
     * @Author: Mr.Yuan
     * @Date:
     */
    @Test
    public void searchIndexByHightlightMatch() throws IOException {
        //    创建搜索请求对象
        SearchRequest searchRequest = new SearchRequest("xc_course");
//    指定类型
        searchRequest.types("doc");
//        搜索源构建对象
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//        设置分页参数
//        设置起始记录数，及每页显示数
        searchSourceBuilder.from(0);
        searchSourceBuilder.size(3);
//        设置排序条件
        searchSourceBuilder.sort("studymodel", SortOrder.ASC);
        searchSourceBuilder.sort("price", SortOrder.DESC);
//        设置高亮显示
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.preTags("<tag>");
        highlightBuilder.postTags("</tag>");
//        添加高亮显示的域
        highlightBuilder.fields().add(new HighlightBuilder.Field("name"));
        highlightBuilder.fields().add(new HighlightBuilder.Field("description"));
//        设置高亮显示
        searchSourceBuilder.highlighter(highlightBuilder);
//        设置搜索方式条件
        MultiMatchQueryBuilder multiMatchQueryBuilder = QueryBuilders.multiMatchQuery("开发 css", "name", "description").minimumShouldMatch("50%").field("name", 5);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        boolQueryBuilder.must(multiMatchQueryBuilder);

//        设置过滤条件
//        boolQueryBuilder.filter(QueryBuilders.termQuery("studymodel","201002"));
//        boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").gt(30).lt(50));


        searchSourceBuilder.query(boolQueryBuilder);
//        设置过滤字段,第一个结果集表示要显示的字段，第二个结果集表示不要显示的字段，
        searchSourceBuilder.fetchSource(new String[]{"name", "description"}, new String[]{});
//        搜索请求中设置搜索源对象
        SearchRequest source = searchRequest.source(searchSourceBuilder);
//        进行搜索
        SearchResponse searchResponse = restHighLevelClient.search(source);
//        搜索的结果
        SearchHits hits = searchResponse.getHits();
//        得到匹配度搞得数据
        SearchHit[] hitsHits = hits.getHits();
        long totalHits = hits.getTotalHits();
        System.out.println(totalHits);


//        遍历结果
        for (SearchHit sh : hitsHits
        ) {
            Map<String, Object> sourceAsMap = sh.getSourceAsMap();
            String name = (String) sourceAsMap.get("name");
            String description = (String) sourceAsMap.get("description");
            //        取出高亮显示内容
            Map<String, HighlightField> highlightFields = sh.getHighlightFields();
            if(highlightFields!=null){
                HighlightField hightname = highlightFields.get("name");
                HighlightField descriptionhight = highlightFields.get("description");
                StringBuffer stringBuffer1=new StringBuffer();
                StringBuffer stringBuffer2=new StringBuffer();
                if(hightname!=null){
//                    取出高亮显示内容
                    Text[] fragments = hightname.getFragments();
                    for (Text t :fragments
                            ) {
                       stringBuffer1.append(t);
                    }
                    name=stringBuffer1.toString();
                }
                if(descriptionhight!=null){
//                    取出高亮显示内容
                    Text[] fragments = descriptionhight.getFragments();
                    for (Text t :fragments
                    ) {
                        stringBuffer2.append(t);
                    }
                    description=stringBuffer2.toString();
                }
            }

            System.out.println(name);
            System.out.println(description);
        }


    }

}
